#include "../src/httpServer.hpp"

extern "C"
{
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}

void GET_Register(const hdp::HttpRequest &request, hdp::HttpResponse *response, const std::string &ip)
{
    std::string rsp;
    hdp::Util::ReadFile("../wwwroot/register.html", &rsp);
    response->SetContent(rsp, "text/html");
}

void GET_Login(const hdp::HttpRequest &request, hdp::HttpResponse *response, const std::string &ip)
{
    std::string rsp;
    hdp::Util::ReadFile("../wwwroot/login.html", &rsp);
    response->SetContent(rsp, "text/html");
}

void GET_Index(const hdp::HttpRequest &request, hdp::HttpResponse *response, const std::string &ip)
{
    std::string rsp;
    hdp::Util::ReadFile("../wwwroot/index.html", &rsp);
    response->SetContent(rsp, "text/html");
}

void Welcome(const hdp::HttpRequest &request, hdp::HttpResponse *response, const std::string &username)
{
    std::string resp;
    hdp::Util::ReadFile("../wwwroot/welcome.html", &resp);
    response->SetContent(resp, "text/html");
}

lua_State *Run_Lua(const std::string &filename)
{
    // 创建一个state luaL_newState返回一个指向堆栈的指针
    lua_State *L = luaL_newstate();
    if (L == NULL)
    {
        LOG_ERROR("luaL_newstate failed");
        return nullptr;
    }
    // 加载 Lua 的所有标准库
    luaL_openlibs(L);

    if (luaL_loadfile(L, filename.c_str()) != LUA_OK)
    {
        const char *error = lua_tostring(L, -1);
        std::cout << "load" << filename << "failed: " << error << std::endl;
        lua_pop(L, 1);
        lua_close(L);
        return nullptr;
    }

    // 运行lua文件
    int ret = lua_pcall(L, 0, 0, 0);
    if (ret)
    {
        const char *error_msg = lua_tostring(L, -1);
        LOG_ERROR("lua_pacll error: {}", error_msg);
        lua_close(L);
        return nullptr;
    }
    return L;
}

void Index(const hdp::HttpRequest &request, hdp::HttpResponse *response, const std::string &ip)
{
    lua_State *L = Run_Lua("index.lua");
    if (L == nullptr)
    {
        LOG_ERROR("Failed to run Lua script");
    }
    lua_getglobal(L, "generate_http_response");
    lua_pushstring(L, ip.c_str());

    /**
     * int lua_pcall(lua_State *L, int nargs, int nresults, int errfunc);
     * L：Lua 状态指针。
     * nargs：传递给 Lua 函数的参数数量。
     * nresults：期望从 Lua 函数返回的结果数量。
     * errfunc：错误处理函数的索引（在 Lua 栈中）,如果为 0,则不使用错误处理函数。
     */
    int ret = lua_pcall(L, 1, 1, 0);
    if (ret)
    {
        const char *err_msg = lua_tostring(L, -1);
        LOG_ERROR("lua_pcall failed: {}", err_msg);
        lua_pop(L, 1);
        return;
    }
    std::string content;
    if (lua_isstring(L, -1))
        content = lua_tostring(L, -1);
    response->SetContent(content, "text/html");
    lua_close(L);
}

void POST_Register(const hdp::HttpRequest &request, hdp::HttpResponse *response, const std::string &ip)
{
    std::string body = request._body;
    Json::CharReaderBuilder crb;
    std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
    Json::Value root;
    std::string err;
    bool ret = cr->parse(body.c_str(), body.c_str() + body.size(), &root, &err);
    if (ret == false)
    {
        LOG_ERROR("json deserializa failed");
        return;
    }
    std::string username = root["username"].asString();
    std::string password = root["password"].asString();

    lua_State *L = Run_Lua("register.lua");
    if (L == nullptr)
    {
        LOG_ERROR("Failed to run Lua script");
    }

    lua_getglobal(L, "register");
    lua_pushstring(L, username.c_str());
    lua_pushstring(L, password.c_str());

    ret = lua_pcall(L, 2, 2, 0);
    if (ret)
    {
        const char *err_msg = lua_tostring(L, -1);
        LOG_ERROR("lua_pcall failed: {}", err_msg);
        lua_pop(L, 1);
        return;
    }

    // 获取返回的布尔值和字符串信息
    bool success = lua_toboolean(L, -2);
    std::string message = lua_tostring(L, -1);
    Json::Value rsp_root;
    rsp_root["success"] = success;
    rsp_root["message"] = message;

    Json::StreamWriterBuilder swb;
    std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
    std::stringstream ss;
    int ans = sw->write(rsp_root, &ss);
    if (ans != 0)
    {
        LOG_ERROR("JSON serialize failed");
        return;
    }

    if (success)
        response->_statu = 200;
    else
        response->_statu = 400;
    response->SetContent(ss.str(), "application/json");

    lua_close(L);
}

void POST_Login(const hdp::HttpRequest &request, hdp::HttpResponse *response, const std::string &ip)
{
    std::string body = request._body;
    Json::CharReaderBuilder crb;
    std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
    Json::Value root;
    std::string err;
    bool ret = cr->parse(body.c_str(), body.c_str() + body.size(), &root, &err);
    if (ret == false)
    {
        LOG_ERROR("json deserializa failed");
        return;
    }
    std::string username = root["username"].asString();
    std::string password = root["password"].asString();
    if (ret == false)
    {
        LOG_ERROR("bad request");
        return;
    }

    lua_State *L = Run_Lua("login.lua");
    if (L == nullptr)
    {
        LOG_ERROR("Failed to run Lua script");
    }

    lua_getglobal(L, "login");
    lua_pushstring(L, username.c_str());
    lua_pushstring(L, password.c_str());

    ret = lua_pcall(L, 2, 2, 0);
    if (ret)
    {
        const char *err_msg = lua_tostring(L, -1);
        LOG_ERROR("lua_pcall failed: {}", err_msg);
        lua_pop(L, 1);
        return;
    }

    // 获取返回的布尔值和字符串信息
    bool success = lua_toboolean(L, -2);
    std::string message = lua_tostring(L, -1);
    Json::Value rsp_root;
    rsp_root["success"] = success;
    rsp_root["message"] = message;

    Json::StreamWriterBuilder swb;
    std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
    std::stringstream ss;
    int ans = sw->write(rsp_root, &ss);
    if (ans != 0)
    {
        LOG_ERROR("JSON serialize failed");
        return;
    }

    if (success)
        response->_statu = 200;
    else
        response->_statu = 400;
    response->SetContent(ss.str(), "application/json");

    lua_close(L);
}

int main()
{
    hdp::init_logger(hdp::Config::GetInstance().run_mode, hdp::Config::GetInstance().log_file, hdp::Config::GetInstance().log_level);

    hdp::HttpServer server(hdp::Config::GetInstance().server_port);
    server.SetThreadCount(hdp::Config::GetInstance().thread_count);
    server.SetBaseDir(hdp::Config::GetInstance().base_dir);

    server.Get("/register", GET_Register);
    server.Post("/register.lua", POST_Register);
    server.Get("/login", GET_Login);
    server.Post("/login.lua", POST_Login);
    server.Get("/index", GET_Index);
    server.Get("/index.lua", Index);
    server.Get("/welcome", Welcome);

    server.Start();
    return 0;
}
